package com.citcc.api.netty.client;



import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.logging.LoggingHandler;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.logging.InternalLogLevel;
import org.jboss.netty.util.HashedWheelTimer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.citcc.api.netty.EchargeConstants;
import com.citcc.api.netty.bean.ConsuMessage;
import com.citcc.api.netty.handle.RecevieHandler;
import com.citcc.api.netty.server.ConsuDecoder;

import java.net.InetSocketAddress;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * @author liyachong
 * @date 2019/4/4
 * @time 11:36
 */
public class TcpClient {

    private static final Logger LOG = LoggerFactory.getLogger(TcpClient.class);

    private static final int DEFAULT_PORT = 8801;

    private long connectTimeoutMillis = 3000;

    private int port = DEFAULT_PORT;

    private boolean tcpNoDelay = false;

    private boolean reuseAddress = true;

    private boolean keepAlive = true;

    private int workerCount = 4;

    private ClientBootstrap bootstrap = null;

    private static Channel channel = null;

    private Executor bossExecutor = Executors.newCachedThreadPool();

    private Executor workerExecutor = Executors.newCachedThreadPool();


    private static TcpClient instance = new TcpClient();

    private TcpClient() {
        init();
    }

    public static TcpClient getInstence() {
        return instance;
    }


    public void init() {
        bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(
                bossExecutor, workerExecutor, workerCount));
        bootstrap.setOption("tcpNoDelay", tcpNoDelay);
        bootstrap.setOption("connectTimeoutMillis", connectTimeoutMillis);
        bootstrap.setOption("reuseAddress", reuseAddress);
        bootstrap.setOption("keepAlive", keepAlive);
    }

    private Channel connect(String host, int port) throws InterruptedException {

        if (null == channel || !channel.isOpen()) {
            /*bootstrap.setOption("writeBufferHighWaterMark", 64 * 1024);
            bootstrap.setOption("writeBufferLowWaterMark", 32 * 1024);*/
            bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
                @Override
                public ChannelPipeline getPipeline() throws Exception {
                    ChannelPipeline pipeline = Channels.pipeline();
					pipeline.addLast("loging", new LoggingHandler(InternalLogLevel.ERROR));
                    /*pipeline.addLast("timeout", new IdleStateHandler(new HashedWheelTimer(), 10, 60, 0));//设置空闲心跳机制
                    pipeline.addLast("heartbeat", new HeartBeatHandler());//心跳发送包处理handler
*/                    pipeline.addLast("decode", new ConsuDecoder());//解码
                    pipeline.addLast("recevieHandler", new RecevieHandler());//反馈数据处理
                    return pipeline;
                }
            });
            ChannelFuture future = bootstrap.connect(new InetSocketAddress(
                    host, port));
            future.awaitUninterruptibly();
            if (future.isSuccess()) {
                channel = future.getChannel();
            } else {
            }
        }

        return channel;
    }

    /**
     * 登录监控平台 * boolean * @return
     */
    public boolean login(String deviceNo) throws Exception{
        boolean success = false;
        if (EchargeConstants.LOGIN_C ==0x02 ) {
            //开始登录 Message为数据对象
            ConsuMessage msg = buildLoginSendVO("");
            ChannelBuffer buffer = ChannelBuffers.buffer(32);
            channel = connect("127.0.0.1", 8801);
            if (null != channel && channel.isWritable()){
                channel.write(buildBuffer(msg));
            }

        }
        return success;
    }

    /**
     * 登录监控平台 * boolean * @return
     */
    public boolean sendHeart(String deviceNo) throws Exception{
        boolean success = false;
        if (EchargeConstants.HEART_C ==0x01 ) {
            //开始登录 Message为数据对象
            ConsuMessage msg = buildHeartSendVO("");
            ChannelBuffer buffer = ChannelBuffers.buffer(23);
            channel = connect("127.0.0.1", 8801);
            if (null != channel && channel.isWritable()){
                channel.write(buildBuffer(msg));
            }

        }
        return success;
    }

    /**
     * 	封装最终的消息  上行消息
     * 	Head flag 头标识 0x75,0x72。
     *  Message Header 数据头   2
     *  End Flag 尾标识 0x68    1
     *  校验和  4
     * @param msg
     * @return
     */
    public  ChannelBuffer buildBuffer(ConsuMessage msg) {
        int bodyLength = 0;
        if (null != msg.getMsgBody()) {
            bodyLength = msg.getMsgBody().readableBytes();
        }
        System.out.println("bodyLength = " + bodyLength);
        ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(bodyLength + 7);
        buffer.writeByte(ConsuMessage.MSG_HEAD_1);
        buffer.writeByte(ConsuMessage.MSG_HEAD_2);
        //---数据体
        if (null != msg.getMsgBody()) {
            buffer.writeBytes(msg.getMsgBody().array());
        }
        buffer.writeByte(ConsuMessage.MSG_END);
        //校验和  登录的
        if(EchargeConstants.LOGIN_C==msg.getMsgId()){
            buffer.writeInt(0xB6030000);
        }
        if(EchargeConstants.HEART_C==msg.getMsgId()){
            buffer.writeInt(0x87020000);
        }
        return ChannelBuffers.copiedBuffer(buffer);
    }



    /**
     * 将bean对象封装到 消息的消息体
     * @param deviceNo
     * @return
     */
    private ConsuMessage buildHeartSendVO(String deviceNo) {
        ConsuMessage msg = new ConsuMessage(EchargeConstants.HEART_C);

        ChannelBuffer bodyBuffer = ChannelBuffers.buffer(14);
        /****数据部分********/
        bodyBuffer.writeShort(0x1300);
        bodyBuffer.writeInt(EchargeConstants.TERMINAL_NO);//终端号
        bodyBuffer.writeByte(msg.getMsgId());//心跳命令
        bodyBuffer.writeByte(0x10);//终端枪号
        bodyBuffer.writeByte(0x02);
        bodyBuffer.writeByte(0x14);
        bodyBuffer.writeInt(0x45560800);
        msg.setMsgBody(bodyBuffer);
        return msg;
    }

    /**
     * 将bean对象封装到 消息的消息体
     * @param deviceNo
     * @return
     */
    private ConsuMessage buildLoginSendVO(String deviceNo) {
        ConsuMessage msg = new ConsuMessage(EchargeConstants.LOGIN_C);

        ChannelBuffer bodyBuffer = ChannelBuffers.buffer(25);
        /****数据部分********/
        bodyBuffer.writeShort(0x1E00);
        bodyBuffer.writeInt(EchargeConstants.TERMINAL_NO);//终端号
        bodyBuffer.writeByte(msg.getMsgId());//登录命令
        bodyBuffer.writeByte(0x10);//终端枪号
        bodyBuffer.writeByte(0x02);
        //命令一下数据为数据体

        // 1//日月年dmyy
        /*Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        bodyBuffer.writeByte((byte) cal.get(Calendar.DATE));
        bodyBuffer.writeByte((byte) (cal.get(Calendar.MONTH) + 1));
        String hexYear = "0" + Integer.toHexString(cal.get(Calendar.YEAR));
        bodyBuffer.writeBytes("19".getBytes());
        //时分秒
        bodyBuffer.writeByte((byte) cal.get(Calendar.HOUR_OF_DAY));
        bodyBuffer.writeByte((byte) cal.get(Calendar.MINUTE));
        bodyBuffer.writeByte((byte) cal.get(Calendar.SECOND));*/
        bodyBuffer.writeInt(0x19200220);
        bodyBuffer.writeShort(0x0936);
        bodyBuffer.writeByte(0x50);
        bodyBuffer.writeByte(0x05);
        bodyBuffer.writeInt(0);
        bodyBuffer.writeInt(0x01070502);
        msg.setMsgBody(bodyBuffer);
        return msg;
    }

    /**
     * 补全位数不够的定长参数 有些定长参数，实际值长度不够，在后面补0x00 * byte[] * @param length * @param pwdByte * @return
     */
    private byte[] getBytesWithLengthAfter(int length, byte[] pwdByte) {
        byte[] lengthByte = new byte[length];
        for (int i = 0; i < pwdByte.length; i++) {
            lengthByte[i] = pwdByte[i];
        }
        for (int i = 0; i < (length - pwdByte.length); i++) {
            lengthByte[pwdByte.length + i] = 0x00;
        }
        return lengthByte;
    }


    public static void main(String[] args) throws Exception{
        new TcpClient().login("");
        //new TcpClient().sendHeart("");

    }
}
